#!/usr/bin/env python

import sqlite3
from math import exp, log, pow
from sys import stderr

def sigmoid(x):
	return (1.0/(1.0+exp(-x)))

def isigmoid(y):
	"""y must be greater than 0 and less than 1"""
	if y <= 0.0:
		y = 0.0000001
	elif y >= 1.0:
		y = 0.9999999

	return -log(1.0/y - 1.0)
def dsigmoid(x):
	"""dy/dx y=sigmoid(x)"""
	return exp(x)/pow(exp(x) + 1, 2)

def average(lst):
	return sum(lst)/float(len(lst))

class Emotion():
	def __init__(self, dbname):
		self.conn = sqlite3.connect(dbname)#{{{
		self.cur = self.conn.cursor()
		"""print current state"""
		emotion = self.get_emotion()
		state = self.get_state()
		for key in emotion.keys():
			print "%8s: %.5f [%s]"%(key, emotion[key], state[key])#}}}

	def get_state(self):
		emotion = self.get_emotion()#{{{
		state = {}
		for key in emotion.keys():
			if emotion[key] < 0.35:
				state[key] = 'low'
			elif emotion[key] > 0.75:
				state[key] = 'high'
			else:
				state[key] = 'normal'

		return state#}}}

	def add_person(self, userid):
		#{{{
		try:
			emotion = self.get_emotion()
			self.cur.execute("insert into personal_emotion(userid, anger, interest, joy, trust, fear, surprise, sadness, disgust)\
					values(%d, %f, %f, %f, %f, %f, %f, %f, %f)"%(userid,
						emotion['anger'], emotion['interest'], emotion['joy'], emotion['trust'],
						emotion['fear'], emotion['surprise'], emotion['sadness'], emotion['disgust']))
			self.conn.commit()
		except sqlite3.OperationalError, e:
			e.print_stack()
		#}}}
	
	def get_persons(self):
		try:#{{{
			self.cur.execute('select userid from personal_emotion')
			rows = self.cur.fetchall()
			rows = map(lambda x: x[0], rows)
			return tuple(rows)
		except sqlite3.OperationalError, e:
			e.print_stack()
			return None;
		#}}}

	def get_emotion(self):
		#{{{
		try:
			self.cur.execute("select anger, interest, joy, trust, fear, surprise, sadness, disgust from global_emotion")
			row = self.cur.fetchone()
			global_emotion = {
					'anger': row[0],
					'interest': row[1],
					'joy': row[2],
					'trust': row[3],
					'fear': row[4],
					'surprise': row[5],
					'sadness': row[6],
					'disgust': row[7],
					}
			return global_emotion
		except sqlite3.OperationalError, e:
			e.print_stack()
			return None
		#}}}

	def get_personal_emotion(self, userid):
		#{{{
		try:
			self.cur.execute("select anger, interest, joy, trust, fear, surprise, sadness, disgust from personal_emotion where userid=%d"%(userid))
			row = self.cur.fetchone()
			if row == None:
				return None
			personal_emotion = {
					'anger': row[0],
					'interest': row[1],
					'joy': row[2],
					'trust': row[3],
					'fear': row[4],
					'surprise': row[5],
					'sadness': row[6],
					'disgust': row[7],
					}
			return personal_emotion
		except sqlite3.OperationalError, e:
			e.print_stack()
			return None#}}}

	def affect_emotion(self, userid, anger=0, interest=0, joy=0, trust=0, fear=0, surprise=0, sadness=0, disgust=0):
		#{{{
		#get current global and personal emotion
		global_emotion = self.get_emotion()
		personal_emotion = self.get_personal_emotion(userid)
		if personal_emotion == None:
			self.add_person(userid)
			personal_emotion = self.get_personal_emotion(userid)

		#calculate deltas
		delta_anger = anger + 0.5*(interest + disgust) - (fear + 0.5*(surprise + trust))
		delta_interest = interest + 0.5*(joy + anger) - (surprise + 0.5*(sadness + fear))
		delta_joy = joy + 0.5*(trust + interest) - (sadness + 0.5*(disgust + surprise))
		delta_trust = trust + 0.5*(fear + joy) - (disgust + 0.5*(anger + sadness))
		delta_fear = fear + 0.5*(surprise + trust) - (anger + 0.5*(interest + disgust))
		delta_surprise = surprise + 0.5*(sadness + fear) - (interest + 0.5*(joy + anger))
		delta_sadness = sadness + 0.5*(disgust + surprise) - (joy + 0.5*(trust + interest))
		delta_disgust = disgust + 0.5*(anger + sadness) - (trust + 0.5*(fear + joy))

		"""
		print "delta_anger is %.3f"%delta_anger
		print "delta_interest is %.3f"%delta_interest
		print "delta_joy is %.3f"%delta_joy
		print "delta_trust is %.3f"%delta_trust
		print "delta_fear is %.3f"%delta_fear
		print "delta_surprise is %.3f"%delta_surprise
		print "delta_sadness is %.3f"%delta_sadness
		print "delta_disgust is %.3f"%delta_disgust
		print ''
		"""

		"""
		adjust deltas by personal emotion
		ex)
		  if AE trust someone, then larger change of joy, fear(friend emotion)
		  if AE surprised by soneone, then smaller change of interest(anti-emotion), joy, anger(anti-friend-emotion)
		"""
		"""multiply 2.0 because middle of isigmoid is 0.5"""
		"""changing macro
:s/m0/anger/g
gv:s/m1/interest/g
gv:s/m2/joy/g
gv:s/m3/trust/g
gv:s/m4/fear/g
gv:s/m5/surprise/g
gv:s/m6/sadness/g
gv:s/m7/disgust/g
		"""

		delta_anger *= 2.0 * average([
			personal_emotion['interest'],
			personal_emotion['disgust'],
			1.0-personal_emotion['fear']])
		delta_interest *= 2.0 * average([
			personal_emotion['joy'],
			personal_emotion['anger'],
			1.0-personal_emotion['surprise']])
		delta_joy *= 2.0 * average([
			personal_emotion['trust'],
			personal_emotion['interest'],
			1.0-personal_emotion['sadness']])
		delta_trust *= 2.0 * average([
			personal_emotion['fear'],
			personal_emotion['joy'],
			1.0-personal_emotion['disgust']])
		delta_fear *= 2.0 * average([
			personal_emotion['surprise'],
			personal_emotion['trust'],
			1.0-personal_emotion['anger']])
		delta_surprise *= 2.0 * average([
			personal_emotion['sadness'],
			personal_emotion['fear'],
			1.0-personal_emotion['interest']])
		delta_sadness *= 2.0 * average([
			personal_emotion['disgust'],
			personal_emotion['surprise'],
			1.0-personal_emotion['joy']])
		delta_disgust *= 2.0 * average([
			personal_emotion['anger'],
			personal_emotion['sadness'],
			1.0-personal_emotion['trust']])

		"""
		calculate global affects weight
		by average of dsigmoids
		"""
		dsigmoids = map(lambda x: dsigmoid(x), personal_emotion.values())
		global_weight = average(dsigmoids)

		"""
		print "global weight is %.3f"%global_weight

		print "delta_anger is %.3f"%delta_anger
		print "delta_interest is %.3f"%delta_interest
		print "delta_joy is %.3f"%delta_joy
		print "delta_trust is %.3f"%delta_trust
		print "delta_fear is %.3f"%delta_fear
		print "delta_surprise is %.3f"%delta_surprise
		print "delta_sadness is %.3f"%delta_sadness
		print "delta_disgust is %.3f"%delta_disgust
		print ''

		print "personal emotion:"
		for key in personal_emotion.keys():
			print "%s: %.3f"%(key, personal_emotion[key])

		print "global emotion:"
		for key in global_emotion.keys():
			print "%s: %.3f"%(key, global_emotion[key])
		"""

		personal_anger = sigmoid( isigmoid(personal_emotion['anger']) + delta_anger)
		personal_interest = sigmoid( isigmoid(personal_emotion['interest']) + delta_interest)
		personal_joy = sigmoid( isigmoid(personal_emotion['joy']) + delta_joy)
		personal_trust = sigmoid( isigmoid(personal_emotion['trust']) + delta_trust)
		personal_fear = sigmoid( isigmoid(personal_emotion['fear']) + delta_fear)
		personal_surprise = sigmoid( isigmoid(personal_emotion['surprise']) + delta_surprise)
		personal_sadness = sigmoid( isigmoid(personal_emotion['sadness']) + delta_sadness)
		personal_disgust = sigmoid( isigmoid(personal_emotion['disgust']) + delta_disgust)

		global_anger = sigmoid( isigmoid(global_emotion['anger']) + global_weight * delta_anger)
		global_interest = sigmoid( isigmoid(global_emotion['interest']) + global_weight * delta_interest)
		global_joy = sigmoid( isigmoid(global_emotion['joy']) + global_weight * delta_joy)
		global_trust = sigmoid( isigmoid(global_emotion['trust']) + global_weight * delta_trust)
		global_fear = sigmoid( isigmoid(global_emotion['fear']) + global_weight * delta_fear)
		global_surprise = sigmoid( isigmoid(global_emotion['surprise']) + global_weight * delta_surprise)
		global_sadness = sigmoid( isigmoid(global_emotion['sadness']) + global_weight * delta_sadness)
		global_disgust = sigmoid( isigmoid(global_emotion['disgust']) + global_weight * delta_disgust)

		self.cur.execute("update global_emotion set anger=%.3f, interest=%.3f, joy=%.3f, trust=%.3f, fear=%.3f, surprise=%.3f, sadness=%.3f, disgust=%.3f"%(global_anger, global_interest, global_joy, global_trust, global_fear, global_surprise, global_sadness, global_disgust));
		self.cur.execute("update personal_emotion set anger=%.3f, interest=%.3f, joy=%.3f, trust=%.3f, fear=%.3f, surprise=%.3f, sadness=%.3f, disgust=%.3f where userid=%d"%(personal_anger, personal_interest, personal_joy, personal_trust, personal_fear, personal_surprise, personal_sadness, personal_disgust, userid));
		self.conn.commit()
		#}}}

	def parse_text(self, userid, text, weight=1.0):
		#{{{
		"""
		calculate about emotion changes
		and call affect_emotion
		@var weight: specialize for mention
		"""
		emotion = {
			'anger': 0,
			'interest': 0,
			'joy': 0,
			'trust': 0,
			'fear': 0,
			'surprise': 0,
			'sadness': 0,
			'disgust': 0,
			}

		self.cur.execute('select word, anger, interest, joy, trust, fear, surprise, sadness, disgust from keywords')
		rows = self.cur.fetchall()
		for row in rows:
			''' affects n * keywordweight '''
			count = text.count(row[0])

			emotion['anger'] += row[1] * count * weight
			emotion['interest'] += row[2] * count * weight
			emotion['joy'] += row[3] * count * weight
			emotion['trust'] += row[4] * count * weight
			emotion['fear'] += row[5] * count * weight
			emotion['surprise'] += row[6] * count * weight
			emotion['sadness'] += row[7] * count * weight
			emotion['disgust'] += row[8] * count * weight

		print "debug parse_text"
		for key in emotion.keys():
			print "%8s: %.5f"%(key, emotion[key])
		self.affect_emotion(userid, **emotion)
		#}}}

if __name__ == "__main__":
	emo = Emotion('emotion.db')
